開始單元測試前,先讓我們設定一下測試範圍,避免執行到 e2e 測試的部分。
vitest 可以和 vite 共用設定檔,所以我們在 vite 新增設定即可。
vite.config.ts
...
export default defineConfig(({ command, mode }) => {
...
return {
...
test: {
include: ['src/**/*.{test,spec}.ts'],
...
},
}
})
現在讓我們新增測試檔案。
src\components\text-characters-transition\text-characters-transition.spec.ts
import { mount } from '@vue/test-utils';
import { test, expect } from 'vitest';
import TextCharactersTransition from './text-characters-transition.vue';
test('測試案例', () => {
const wrapper = mount(TextCharactersTransition);
expect(wrapper).toBeDefined();
})
讓我們依序新增各種測試案例吧。∠( ᐛ 」∠)_
src\components\text-characters-transition\text-characters-transition.spec.ts
...
test('容器可以指定 HTML tag', () => {
const tag = 'span';
const wrapper = mount(TextCharactersTransition, {
props: {
label: '文字',
tag,
},
});
const container = wrapper.find('[aria-label]');
expect(container.element.tagName).toBe('SPAN');
})
describe('容器之 aria-label 必須等於 label', () => {
test('label 為 string', () => {
const label = '文字';
const wrapper = mount(TextCharactersTransition, {
props: { label },
});
const container = wrapper.find('[aria-label]');
expect(container.element.tagName).toBe('P');
expect(container.attributes('aria-label')).toBe(label);
})
test('label 為 string[]', () => {
const label = ['文字文字文字', '文字文字文字'];
const wrapper = mount(TextCharactersTransition, {
props: { label },
});
const container = wrapper.find('[aria-label]');
expect(container.attributes('aria-label')).toBe(label.join(''));
const list = wrapper.findAll('span');
expect(list).toHaveLength(label.length);
})
})
test('被拆分的 span 數量必須等於 label 字數', () => {
const label = '文字文字文字文字文字';
const wrapper = mount(TextCharactersTransition, {
props: { label },
});
const list = wrapper.findAll('span');
expect(list).toHaveLength(label.length);
})
再來是 splitter。
src\components\text-characters-transition\text-characters-transition.spec.ts
...
describe('splitter 指定拆分方式', () => {
test('根據「,」拆分', () => {
const splitter = /(,)/;
const label = '文字文字,文字文字,文字';
const wrapper = mount(TextCharactersTransition, {
props: { label, splitter },
});
const list = wrapper.findAll('span');
expect(list).toHaveLength(
label.split(splitter).length
);
})
test('自定義拆分 function', async () => {
const label = '文字文字文字文字文字';
const splitter = (text: string) => {
if (text.includes('鱈魚')) {
return text.split('鱈魚');
}
return text.split('');
};
const wrapper = mount(TextCharactersTransition, {
props: { label, splitter },
});
const list = wrapper.findAll('span');
expect(list).toHaveLength(label.length);
const newLabel = '文字文字鱈魚文字文字';
await wrapper.setProps({ label: newLabel });
const newList = wrapper.findAll('span');
expect(newList).toHaveLength(
splitter(newLabel).length
);
})
})
最後是切換 visible 會觸發對應事件部分。
src\components\text-characters-transition\text-characters-transition.spec.ts
...
test('切換 visible 會觸發對應事件', async () => {
const wrapper = mount(TextCharactersTransition, {
props: {
visible: false,
label: '文字文字',
},
});
expect(wrapper.emitted()).not.toHaveProperty('before-enter');
expect(wrapper.emitted()).not.toHaveProperty('after-enter');
await wrapper.setProps({ visible: true });
await promiseTimeout(2000);
expect(wrapper.emitted()).toHaveProperty('before-enter');
expect(wrapper.emitted()).toHaveProperty('after-enter');
})
這次的測試相當順利!(/≧▽≦)/
✓ src/components/text-characters-transition/text-characters-transition.spec.ts (7) 2060ms
✓ 容器可以指定 HTML tag
✓ 容器之 aria-label 必須等於 label (2)
✓ label 為 string
✓ label 為 string[]
✓ 被拆分的 span 數量必須等於 label 字數
✓ splitter 指定拆分方式 (2)
✓ 根據「,」拆分
✓ 自定義拆分 function
✓ 切換 visible 會觸發對應事件 2005ms
Test Files 1 passed (1)
Tests 7 passed (7)
Start at 23:42:25
Duration 2.38s
以上程式碼已同步至 GitLab,大家可以前往下載: